package com.heisen.hander;

import com.heisen.base.entity.Api;
import com.heisen.base.exception.RRException;
import enums.ApiReturnEnums;
import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.Map;
import java.util.concurrent.TimeoutException;

@Slf4j
public class GatewayExceptionHandler  extends DefaultErrorWebExceptionHandler {
    /**
     * Create a new {@code DefaultErrorWebExceptionHandler} instance.
     *
     * @param errorAttributes    the error attributes
     * @param resourceProperties the resources configuration properties
     * @param errorProperties    the error configuration properties
     * @param applicationContext the current application context
     */
    public GatewayExceptionHandler(ErrorAttributes errorAttributes,
                                   WebProperties resourceProperties,
                                   ErrorProperties errorProperties,
                                   ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties.getResources(), errorProperties, applicationContext);
    }


    /**
     * 异常处理，定义返回报文格式
     */
    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {


        ApiReturnEnums apiReturnEnums = null;

        Throwable error = super.getError(request);
        log.error(
                "请求发生异常，请求URI：{}，请求方法：{}，异常信息：{}",
                request.path(), request.methodName(), error.getMessage()
        );

        if (error instanceof NotFoundException) {  //无法找到该服务
            String serverId = StringUtils.substringAfterLast(error.getMessage(), "Unable to find instance for ");
            serverId = StringUtils.replace(serverId, "\"", StringUtils.EMPTY);
            String msg = String.format(ApiReturnEnums.SERVICE_NO_FIND.getDesc(), serverId);
            ApiReturnEnums.SERVICE_NO_FIND.setDesc(msg);
            apiReturnEnums = ApiReturnEnums.SERVICE_NO_FIND;
        } else if (StringUtils.containsIgnoreCase(error.getMessage(), "connection refused")) {
            apiReturnEnums = ApiReturnEnums.SERVICE_NO_LINK;   //目标服务拒绝连接
        } else if (error instanceof TimeoutException) {
            apiReturnEnums = ApiReturnEnums.SERVICE_TIME_OUT;  //服务超时
        } else if (error instanceof ResponseStatusException
                && StringUtils.containsIgnoreCase(error.getMessage(), HttpStatus.NOT_FOUND.toString())) {
            apiReturnEnums = ApiReturnEnums.RESCOUSE_NO_FIND;//未找到该资源
        }
        else if (error instanceof RRException){
            apiReturnEnums = ApiReturnEnums.VISIT_OVERRUN;//访问频率超限
        }

        else {
            apiReturnEnums = ApiReturnEnums.GETAWAY_INTRANSITE_EXCEPTION;  //网关转发异常
        }
        return Api.makeJsonByEnums(apiReturnEnums);
    }


    @Override
    @SuppressWarnings("all")
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }


    /**
     * 根据code获取对应的HttpStatus
     *
     * @param errorAttributes
     * @return
     */
    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {

        return 200;
    }
}
